﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Data;
using DbSharp.Framework.TestEngine;
using DbSharp.Framework.ReleaseManage;
using DbSharp.Framework.Driver;
using DbSharp.Framework.Common;

namespace DbSharp.Framework.DbObject
{
    public class TransactionController : IDisposable
    {
        #region Private members
        private bool m_AutoRollback;
        private Dictionary<string, ITestDataSource> m_DictConnectionSource = new Dictionary<string, ITestDataSource>();
        private List<DbConnection> m_ListConnection = new List<DbConnection>();
        private List<DbTransaction> m_ListTransaction = new List<DbTransaction>();
        
        #endregion

        public TransactionController(bool autoRollback, bool hasSetupOrTeardown)
        {
            DetectSoftwareLicense();

            m_AutoRollback = autoRollback;
            if (m_AutoRollback)
                DetectTestInSandboxSupported();
            if (hasSetupOrTeardown)
                DetectSetupTeardownSupported();
        }

        #region Private methods

        private void Rollback()
        {
            foreach (DbTransaction trans in m_ListTransaction)
            {
                if (trans != null)
                    trans.Rollback();
            }
        }

        private void CloseConnections()
        {
            foreach (var conn in m_ListConnection)
            {
                if (conn != null)
                {
                    if ((conn.State != ConnectionState.Closed) && (conn.State != ConnectionState.Broken))
                        conn.Close();
                }
            }
        }

        /// <summary>
        /// Detect the software is expired or not
        /// </summary>
        /// <exception cref="ApplicationException">
        /// an exception will be raised if expired.
        /// </exception>
        private void DetectSoftwareExpired(ITestDataSource testDataSource, DbConnection dbConn)
        {
            bool expired = RuntimeInfo.GetInstance().IsSoftwareExpired(testDataSource, dbConn);
            if (expired)
                throw new DbSharpException(SensitiveMessage.SoftwareExpiredMsg1);
        }

        private void DetectSoftwareLicense()
        {
            bool valid = RuntimeInfo.GetInstance().IsValidLicense();
            if (valid == false)
            {
                throw new DbSharpException(SensitiveMessage.InvalidLicenseMsg);
            }
        }


        private void DetectTestInSandboxSupported()
        {
            bool supported = RuntimeInfo.GetInstance().TestInSandboxSupported;
            if (supported == false)
                throw new DbSharpException(SensitiveMessage.SandboxNotSupportedMsg);
        }


        private void DetectSetupTeardownSupported()
        {
            bool supported = RuntimeInfo.GetInstance().SetupTeardownSupported;
            if (supported == false)
                throw new DbSharpException(SensitiveMessage.UnitTestSetupNotSupportedMsg);
        }
        #endregion


        #region Public property/methods




        public DbConnection OpenDbConnection(string connectionString, ITestDataSource testDataSource)
        {
            DbConnection connection = null;
            if ((testDataSource == null) || (string.IsNullOrEmpty(connectionString)))
                return connection;

            connectionString = connectionString.Trim();
            string connectionUpperString = connectionString.ToUpper();
            if (!m_DictConnectionSource.ContainsKey(connectionUpperString))
            {
                m_DictConnectionSource.Add(connectionUpperString, testDataSource);
                connection = testDataSource.CreateConnection(connectionString);
                m_ListConnection.Add(connection);
                connection.Open();

                DetectSoftwareExpired(testDataSource, connection);

                DbTransaction transaction = null;
                if (m_AutoRollback && testDataSource.TransactionSupported)
                {
                    transaction = connection.BeginTransaction();
                }
                m_ListTransaction.Add(transaction);
            }
            else
            {
                int index = -1;
                foreach (var item in m_DictConnectionSource)
                {
                    index++;
                    if (string.Equals(item.Key, connectionString, StringComparison.OrdinalIgnoreCase))
                        break;
                }
                connection = m_ListConnection[index];
            }
            return connection;
        }


        public DbTransaction GetTransaction(string connectionString)
        {
            DbTransaction result = null;
            if  (string.IsNullOrEmpty(connectionString))
                return result;
            connectionString = connectionString.Trim().ToUpper();

            int index = -1;
            foreach (var item in m_DictConnectionSource)
            {
                index++;
                if (string.Equals(item.Key, connectionString))
                    break;
            }
            result = m_ListTransaction[index];
            return result;
        }

        #endregion


        #region IDisposable Members

        public void Dispose()
        {
            try
            {
                if (m_AutoRollback)
                    Rollback();
            }
            finally
            {
                CloseConnections();
            }
        }

        #endregion
    }
}
